package com.hd123.rumba.qt.def;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.type.Type;

import com.hd123.rumba.action.qt.ViewQuery;
import com.hd123.rumba.cartridge.ICartFunctionView;
import com.hd123.rumba.cartridge.ICartridgeMgr;
import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.log.RumbaLogger;
import com.hd123.rumba.qt.IQueryMgr;
import com.hd123.rumba.qt.QTConstants;
import com.hd123.rumba.qt.result.IQueryResultMgr;
import com.hd123.rumba.qt.result.QueryResultDescription;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.user.CPermissionProvider;
import com.hd123.rumba.user.IPermission;
import com.hd123.rumba.user.IPermissionMgr;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.user.PermissionProvider;

public class QueryDefinitionMgr extends Manager implements IQueryDefinitionMgr {

  private static RumbaLogger logger = RumbaLogger.getLogger(QueryDefinitionMgr.class);

  public QueryDefinition getQueryDefinition(IQueryDef queryDef) throws BusinessException,
      HibernateException {
    if (!queryDef.getFile().exists())
      throw new BusinessException("找不到查询定义文件：" + queryDef.getRelativeFilename());
    QueryDefinition qd = new QueryDefinition();
    qd.setFile(queryDef.getFile());
    qd.load();
    return qd;
  }

  public QueryDefinition getQueryDefinition(QueryResultDescription qrd) throws BusinessException,
      HibernateException {
    return getQueryDefinition(getQueryDef(qrd.getQdUuid()));
  }

  public File saveFile(String folder, String name, InputStream content, IUser user)
      throws BusinessException, HibernateException {
    String base = QTConstants.QDHOME;
    File file = new File(base + folder, name);
    try {
      if (!file.getParentFile().exists())
        file.getParentFile().mkdirs();
      file.getParentFile().getParent();
      FileOutputStream fos = new FileOutputStream(file);
      byte abyte0[] = new byte[1024];
      int bytesRead, len = 0;
      while (-1 != (bytesRead = content.read(abyte0, 0, abyte0.length))) {
        len += bytesRead;
        fos.write(abyte0, 0, bytesRead);
      }
      fos.flush();
      fos.close();
    } catch (Exception e) {
      throw new BusinessException(e);
    }
    return file;
  }

  public IQueryDef createQueryDef(IDomain domain) throws BusinessException, HibernateException {
    IQueryDef queryDef = new QueryDef();
    queryDef.setDomain(domain);
    return queryDef;
  }

  public IQueryDef getQueryDef(String uuid) throws BusinessException, HibernateException {
    return (IQueryDef) getSession().get(IQueryDef.class, uuid);
  }

  public IQueryDef getQueryDefByFile(String location, String filename) throws BusinessException,
      HibernateException {
    List list = null;
    if (location != null && location.trim().length() > 0 && !"/".equals(location))
      list = getSession().find(
          "from " + IQueryDef.class.getName()
              + " o where (o.location = ? or o.location = ?) and o.filename = ?", new Object[] {
              location, "/" + location, filename }, new Type[] {
              Hibernate.STRING, Hibernate.STRING, Hibernate.STRING });
    else
      list = getSession().find(
          "from " + IQueryDef.class.getName()
              + " o where (o.location is null or o.location = ?) and o.filename = ?", new Object[] {
              "/", filename }, new Type[] {
              Hibernate.STRING, Hibernate.STRING });
    if (list.size() > 0)
      return (IQueryDef) list.get(0);
    else
      return null;
  }

  public void saveQueryDef(IQueryDef queryDef, List<String> cfvUuids, OperateContext operCtx)
      throws BusinessException, HibernateException {
    ICartridgeMgr cartMgr = (ICartridgeMgr) NamingMgr.getInstance().lookupMgr(ICartridgeMgr.class);
    queryDef.setLastModified(operCtx.getTime());
    queryDef.setLastModifier(operCtx.getOperator().getNameCode());
    // 获得新增的和删除的相关功能视图
    List<ICartFunctionView> deleted = new ArrayList<ICartFunctionView>();
    List<ICartFunctionView> inserted = new ArrayList<ICartFunctionView>();
    for (IQueryDefFuncView qdfv : queryDef.getFucvViews()) {
      if (!cfvUuids.contains(qdfv.getFuncView().getUuid()))
        deleted.add(qdfv.getFuncView());
    }
    for (String cfvUuid : cfvUuids) {
      boolean exists = false;
      for (int i = 0; i < queryDef.getFucvViews().size(); i++) {
        IQueryDefFuncView qdfv = queryDef.getFucvViews().get(i);
        if (qdfv.getFuncView().getUuid().equals(cfvUuid)) {
          exists = true;
          break;
        }
      }
      if (!exists)
        inserted.add(cartMgr.getFunctionView(cfvUuid));
    }
    // 更新查询定义
    queryDef.getFucvViews().clear();
    for (String cfvUuid : cfvUuids) {
      ICartFunctionView cfv = cartMgr.getFunctionView(cfvUuid);
      if (cfv != null) {
        IQueryDefFuncView qdfv = new QueryDefFuncView();
        qdfv.setQueryDef(queryDef);
        qdfv.setFuncView(cfv);
        queryDef.getFucvViews().add(qdfv);
      }
    }
    // 添加权限到功能视图
    for (ICartFunctionView cfv : deleted)
      queryDefRemovePermissions(queryDef, cfv, operCtx);
    for (ICartFunctionView cfv : inserted)
      queryDefInitPermissions(queryDef, cfv, operCtx);

    getSession().saveOrUpdate(queryDef);
  }

  public IQueryDef getNextQueryDefByName(IQueryDef queryDef, String nextQueryName)
      throws BusinessException, HibernateException {
    QueryDefinition qd = this.getQueryDefinition(queryDef);
    SQLNCriteriaListList nexts = qd.getNcriterias();
    boolean exists = false;
    for (int i = 0; i < nexts.size(); i++) {
      SQLNCriteriaList nc = (SQLNCriteriaList) nexts.get(i);
      if (nextQueryName.equals(nc.getNextQuery())) {
        exists = true;
        break;
      }
    }
    if (!exists)
      throw new BusinessException("找不到当前查询的下一查询：" + nextQueryName + " 。");
    nextQueryName = nextQueryName.replace('\\', '/');
    String location = queryDef.getLocation();
    String filename = nextQueryName;
    int index = nextQueryName.lastIndexOf("/");
    if (index >= 0) {
      location = location + nextQueryName.substring(0, index);
      filename = nextQueryName.substring(index + 1);
    }
    return getQueryDefByFile(location, filename);
  }

  private IPermission queryDefInitPermissions(IQueryDef queryDef, ICartFunctionView cfv,
      OperateContext operCtx) throws BusinessException, HibernateException {
    IPermissionMgr permMgr = (IPermissionMgr) NamingMgr.getInstance().lookupMgr(
        IPermissionMgr.class);
    String permName = queryDef.getPermissionName();
    String permCode = cfv.getPrefix() + "." + permName;
    IPermission perm = permMgr.getPermissionByCode(permCode);
    if (perm == null) {
      perm = permMgr.createPermission(permCode, permName);
      perm.setCartFuncViewUuid(cfv.getUuid());
      perm.setProvider(new PermissionProvider());
      perm.getProvider().setType(CPermissionProvider.VALUE_TYPE_ACTION);
      perm.getProvider().setClassName(ViewQuery.class.getName());
      perm.getProvider().setCaption(ViewQuery.CAPTION_VIEW);
      logger.debug("创建权限: " + permCode);
      permMgr.savePermission(perm);
      IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
      userMgr.assignPermissionToUser(perm, operCtx.getOperator(), operCtx);
      logger.debug("添加权限 " + permCode + " 给用户 " + operCtx.getOperator().getNameCode());
      operCtx.getOperator().addToPermissionMap(perm);
    }
    return perm;
  }

  private void queryDefRemovePermissions(IQueryDef queryDef, ICartFunctionView cfv,
      OperateContext operCtx) throws BusinessException, HibernateException {
    IPermissionMgr permMgr = (IPermissionMgr) NamingMgr.getInstance().lookupMgr(
        IPermissionMgr.class);
    String permName = queryDef.getPermissionName();
    String permCode = cfv.getPrefix() + "." + permName;
    IPermission perm = permMgr.getPermissionByCode(permCode);
    if (perm != null) {
      logger.debug("删除权限: " + permCode);
      permMgr.removePermission(perm);
      operCtx.getOperator().removeFromPermissionMap(perm);
    }
  }

  public void removeDef(IQueryDef queryDef, OperateContext operCtx) throws BusinessException,
      HibernateException {
    IQueryMgr qm = (IQueryMgr) NamingMgr.getInstance().lookupMgr(IQueryMgr.class);
    IQueryResultMgr qrm = (IQueryResultMgr) NamingMgr.getInstance()
        .lookupMgr(IQueryResultMgr.class);
    List<QueryResultDescription> qrds = qrm.findAllResults(queryDef.getUuid());
    for (int i = 0; i < qrds.size(); i++) {
      QueryResultDescription qrd = qrds.get(i);
      String tableName = qrd.getTableName();
      if (!qrd.getResultCount().equals(QueryResultDescription.RESULTCOUNT_ERROR))
        qm.deleteTable(tableName);
      qrm.removeQrd(qrd);
    }
    for (IQueryDefFuncView qdfv : queryDef.getFucvViews())
      queryDefRemovePermissions(queryDef, qdfv.getFuncView(), operCtx);
    logger.debug("删除查询文件: " + queryDef.getFullFilename());
    if (queryDef.getFile().exists())
      queryDef.getFile().delete();
    queryDef.getFile().delete();
    if (queryDef.getTemplateFile().exists())
      queryDef.getTemplateFile().delete();
    getSession().delete(queryDef);
  }

  public List<IQueryDef> getQueryDefsByUser(IDomain domain, IUser user) throws BusinessException,
      HibernateException {
    IDomainMgr domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    List<ICartFunctionView> cfvs = domainMgr.getCFVsByDomain(domain);

    List<IQueryDef> list = new ArrayList<IQueryDef>();
    Iterator iter = (Iterator) getSession().iterate(
        "from " + IQueryDef.class.getName() + " o order by o.location");
    while (iter.hasNext()) {
      IQueryDef queryDef = (IQueryDef) iter.next();
      for (ICartFunctionView cfv : cfvs) {
        if (user.hasPermission(queryDef.getCFVPermissionName(cfv))) {
          list.add(queryDef);
          break;
        }
      }
    }
    return list;
  }

}
